Started: 2020-09-10
Last edited: 2020-10-04 21:47:54

library(tidyverse)

# single cell
library(Seurat)

# plotting
library(patchwork)
library(ggthemes)

1 Background

Alice had performed bulk-RNA seq on the placenta sample from COVID-19 positive mothers and control placentas and has a list of genes that were differentially expressed. Here we will use the single-cell RNA seq data to figure out in which cell types those DE genes are expressed.

2 Data

I have already annotated the clusters. The annotated data (a seurat object) was saved as .rds, which we have to read.

seur <- readRDS("../results/02_annotation/seurat-object_annotated.rds")
# set active assay
DefaultAssay(seur) <- "SCT"

# set levels for idents (use merged_annotations)
seur@meta.data$annotation_merged <- factor(seur@meta.data$annotation_merged,
                                           levels = sort(unique(seur@meta.data$annotation_merged)))

# set idents
Idents(seur) <- seur@meta.data$annotation_merged

3 DE genes

Below are the DE genes sent by Alice.

genes <- list()

genes$focused <- c("HSPA1A", "PPP1R11", "LY6GLY6C", "ITGAX", "IFITM1", "C1QC", "CCL2", "OAS3", "MX1")
genes$analysis1 <- c("HSPA1A", "FMC1-LUC7L2", "HSPA1B", "AC011511.4", "PPP1R11", "AL139300.1", "LY6GLY6C")
genes$analysis2 <- c("ITGAX", "OAS3", "IFITM1", "MX1", "C1QC", "MX2", "CCL2")
genes$additional <- c("C1QTNF2", "LYVE1", "TREM1", "FOLR2", "C1QB", "CCL2", "TNFRSF10C", "CXCL9", "IL1R2", "IL36A", "CD28", "OAS1", "IL1RN", "CD36", "CXCR2",   "SERPING1", "CXCR1", "TNFRSF10C", "C1QA", "HCST", "IL36A", "IL4R", "LY96", "IL1R2", "CXCR2", "CXCL2", "S100A7", "IFITM3", "SELENOM", "SELENOP", "C3AR1", "CCL2", "CCL8")
genes$entry <- c("ACE2", "TMPRSS2", "BSG", "DPP4", "CTSL", "CTSB", "FURIN")

all.genes <- c(genes$focused, genes$analysis1, genes$analysis2, genes$additional, genes$entry) %>% 
  unique() %>% 
  sort()

4 Plots

4.1 Dotplot for all genes

# dotplot function
DotPlot2 <- function(object = seur, assay = "SCT", features, title = "", ...) {
  p <- DotPlot(object, 
               assay = assay,
               features = features, 
               dot.scale = 4, 
               dot.min = 0.01,
               ...) +
    coord_flip() +
    labs(caption = paste0("sctransform normalized expression"), title = title) +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
          panel.grid.minor = element_blank(),
          panel.grid.major = element_line(size = 0.1),
          legend.key.size = unit(0.75, "line"))
  
  return(p)
}
DotPlot2(features = all.genes)
The following requested variables were not found: AC011511.4, AL139300.1, FMC1-LUC7L2, LY6GLY6C

cowplot::ggsave2(last_plot(), 
                 filename = "../results/03_de-genes/plots/dotplot_all-genes.pdf", 
                 width = 6.5, height = 8, units = "in")

4.2 Individual genes

# violin function
VlnPlot2 <- function(object = seur, assay = "SCT", feature, ...) {
  p <- VlnPlot(object = object, 
               features = feature, 
               assay = assay, 
               same.y.lims = FALSE,
               split.by = "covid", 
               split.plot = TRUE,
               pt.size = 0,
               ...) + 
    coord_cartesian(clip = "off") +
    theme_classic() +
    theme(
      plot.title = element_text(size = 7, colour = "black"),
      panel.grid.minor = element_blank(),
      panel.grid.major = element_line(size = 0.2),
      axis.line = element_line(size = 0.25),
      axis.ticks = element_line(size = 0.25),
      axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5, 
                                 size = 6, color = "black"),
      axis.title.x = element_blank(),
      axis.title.y = element_text(size = 6, color = "black"),
      axis.text.y = element_text(size = 6, color = "black"),
      legend.key.size = unit(0.50, "lines"),
      legend.position = c(1, 1),
      legend.direction = "horizontal",
      legend.justification = c(1, 0),
      legend.text = element_text(size = 6, colour = "black")
    )
  
  p$layers[[1]]$aes_params$size = 0.25 # violin stroke
  
  return(p)
}
# umap function
FeaturePlot2 <- function(object = seur, feature, ...) {
  DefaultAssay(object) <- "SCT"
  FeaturePlot(object, 
              feature = feature, 
              split.by = "covid",
              pt.size = 0.1, 
              order = TRUE, 
              min.cutoff = "q10", 
              combine = TRUE,
              ...) &
    plot_annotation(title = feature) &
    theme_bw() +
    theme(panel.grid.major = element_line(size = 0.25),
          panel.grid.minor = element_blank(),
          legend.key.size = unit(0.50, "line"),
          legend.text = element_text(size = 6, angle = 90, hjust = 1),
          legend.position = "bottom",
          axis.title = element_text(size = 6),
          plot.title = element_text(size = 7),
          axis.title.y.right = element_blank(),
          axis.text = element_blank(),
          aspect.ratio = 1)
}

for(i in all.genes[all.genes %in% rownames(seur)]) {
  vplot <- VlnPlot2(feature = i)
  fplot <- FeaturePlot2(feature = i, max.cutoff = "q99")
  
  cowplot::ggsave2(vplot, 
                   filename = paste0("../results/03_de-genes/plots/", i, "_violinplot.pdf"),
                   width = 3.5, height = 2, units = "in")
  
  cowplot::ggsave2(fplot, 
                   filename = paste0("../results/03_de-genes/plots/", i, "_on-umap.png"),
                   width = 3.5, height = 2.5, units = "in")
  
  vf <- vplot + fplot + 
  plot_layout(ncol = 1, widths = c(1, 0.5))
  print(vf)
}

For some genes, the umap plots and violin plots seem to disagree with each other. That is, the gene is expressed at higher level in “covid” than “control” according to the violin plot, but the colours appear stronger for “control” on umap plots. I think this is simply because of the differing number of cells from “control” and “covid”. We have fewer cells from “covid” samples (as is evident also on the umap plots), so the lightness or sparseness of blue on umap plots just reflect that. Violin plots on the other hand scale the width of violins to the total number of cells in each group, so this difference is not seen in violin plots.

5 Session Info

sessionInfo()
R version 4.0.2 (2020-06-22)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Mojave 10.14.6

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] ggthemes_4.2.0  patchwork_1.0.1 Seurat_3.2.1    forcats_0.5.0   stringr_1.4.0   dplyr_1.0.2     purrr_0.3.4    
 [8] readr_1.3.1     tidyr_1.1.2     tibble_3.0.3    ggplot2_3.3.2   tidyverse_1.3.0

loaded via a namespace (and not attached):
  [1] Rtsne_0.15            colorspace_1.4-1      deldir_0.1-28         ellipsis_0.3.1        ggridges_0.5.2       
  [6] fs_1.5.0              spatstat.data_1.4-3   rstudioapi_0.11       farver_2.0.3          leiden_0.3.3         
 [11] listenv_0.8.0         ggrepel_0.8.2         fansi_0.4.1           lubridate_1.7.9       xml2_1.3.2           
 [16] codetools_0.2-16      splines_4.0.2         knitr_1.29            polyclip_1.10-0       jsonlite_1.7.1       
 [21] broom_0.7.0           ica_1.0-2             cluster_2.1.0         dbplyr_1.4.4          png_0.1-7            
 [26] uwot_0.1.8            shiny_1.5.0           sctransform_0.2.1     compiler_4.0.2        httr_1.4.2           
 [31] backports_1.1.9       assertthat_0.2.1      Matrix_1.2-18         fastmap_1.0.1         lazyeval_0.2.2       
 [36] cli_2.0.2             later_1.1.0.1         htmltools_0.5.0       tools_4.0.2           rsvd_1.0.3           
 [41] igraph_1.2.5          gtable_0.3.0          glue_1.4.2            RANN_2.6.1            reshape2_1.4.4       
 [46] spatstat_1.64-1       Rcpp_1.0.5            cellranger_1.1.0      vctrs_0.3.4           nlme_3.1-149         
 [51] lmtest_0.9-38         xfun_0.16             globals_0.12.5        rvest_0.3.6           mime_0.9             
 [56] miniUI_0.1.1.1        lifecycle_0.2.0       irlba_2.3.3           goftest_1.2-2         future_1.18.0        
 [61] MASS_7.3-52           zoo_1.8-8             scales_1.1.1          spatstat.utils_1.17-0 hms_0.5.3            
 [66] promises_1.1.1        parallel_4.0.2        RColorBrewer_1.1-2    yaml_2.2.1            reticulate_1.16      
 [71] pbapply_1.4-3         gridExtra_2.3         rpart_4.1-15          stringi_1.5.3         rlang_0.4.7          
 [76] pkgconfig_2.0.3       matrixStats_0.56.0    lattice_0.20-41       tensor_1.5            ROCR_1.0-11          
 [81] labeling_0.3          htmlwidgets_1.5.1     cowplot_1.1.0         tidyselect_1.1.0      RcppAnnoy_0.0.16     
 [86] plyr_1.8.6            magrittr_1.5          R6_2.4.1              generics_0.0.2        DBI_1.1.0            
 [91] mgcv_1.8-31           pillar_1.4.6          haven_2.3.1           withr_2.2.0           fitdistrplus_1.1-1   
 [96] abind_1.4-5           survival_3.2-3        future.apply_1.6.0    modelr_0.1.8          crayon_1.3.4         
[101] KernSmooth_2.23-17    plotly_4.9.2.1        grid_4.0.2            readxl_1.3.1          data.table_1.13.0    
[106] blob_1.2.1            reprex_0.3.0          digest_0.6.25         xtable_1.8-4          httpuv_1.5.4         
[111] munsell_0.5.0         viridisLite_0.3.0    
LS0tCnRpdGxlOiAiRXhwcmVzc2lvbiBvZiBERSBnZW5lcyIKYXV0aG9yOiAiQXJ1biBDaGF2YW4iCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKYmlibGlvZ3JhcGh5OiAuLi9yZWZzLmJpYgotLS0KU3RhcnRlZDogMjAyMC0wOS0xMCAgCkxhc3QgZWRpdGVkOiBgciBmb3JtYXQoU3lzLnRpbWUoKSlgCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKCiMgc2luZ2xlIGNlbGwKbGlicmFyeShTZXVyYXQpCgojIHBsb3R0aW5nCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGdndGhlbWVzKQpgYGAKCgojIEJhY2tncm91bmQKQWxpY2UgaGFkIHBlcmZvcm1lZCBidWxrLVJOQSBzZXEgb24gdGhlIHBsYWNlbnRhIHNhbXBsZSBmcm9tIENPVklELTE5IHBvc2l0aXZlIG1vdGhlcnMgYW5kIGNvbnRyb2wgcGxhY2VudGFzIGFuZCBoYXMgYSBsaXN0IG9mIGdlbmVzIHRoYXQgd2VyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQuIEhlcmUgd2Ugd2lsbCB1c2UgdGhlIHNpbmdsZS1jZWxsIFJOQSBzZXEgZGF0YSB0byBmaWd1cmUgb3V0IGluIHdoaWNoIGNlbGwgdHlwZXMgdGhvc2UgREUgZ2VuZXMgYXJlIGV4cHJlc3NlZC4gCgojIERhdGEKSSBoYXZlIGFscmVhZHkgYW5ub3RhdGVkIHRoZSBjbHVzdGVycy4gVGhlIGFubm90YXRlZCBkYXRhIChhIGBzZXVyYXRgIG9iamVjdCkgd2FzIHNhdmVkIGFzIGAucmRzYCwgd2hpY2ggd2UgaGF2ZSB0byByZWFkLiAKCmBgYHtyfQpzZXVyIDwtIHJlYWRSRFMoIi4uL3Jlc3VsdHMvMDJfYW5ub3RhdGlvbi9zZXVyYXQtb2JqZWN0X2Fubm90YXRlZC5yZHMiKQpgYGAKCmBgYHtyfQojIHNldCBhY3RpdmUgYXNzYXkKRGVmYXVsdEFzc2F5KHNldXIpIDwtICJTQ1QiCgojIHNldCBsZXZlbHMgZm9yIGlkZW50cyAodXNlIG1lcmdlZF9hbm5vdGF0aW9ucykKc2V1ckBtZXRhLmRhdGEkYW5ub3RhdGlvbl9tZXJnZWQgPC0gZmFjdG9yKHNldXJAbWV0YS5kYXRhJGFubm90YXRpb25fbWVyZ2VkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gc29ydCh1bmlxdWUoc2V1ckBtZXRhLmRhdGEkYW5ub3RhdGlvbl9tZXJnZWQpKSkKCiMgc2V0IGlkZW50cwpJZGVudHMoc2V1cikgPC0gc2V1ckBtZXRhLmRhdGEkYW5ub3RhdGlvbl9tZXJnZWQKYGBgCgojIERFIGdlbmVzCkJlbG93IGFyZSB0aGUgREUgZ2VuZXMgc2VudCBieSBBbGljZS4gCgpgYGB7cn0KZ2VuZXMgPC0gbGlzdCgpCgpnZW5lcyRmb2N1c2VkIDwtIGMoIkhTUEExQSIsICJQUFAxUjExIiwgIkxZNkdMWTZDIiwgIklUR0FYIiwgIklGSVRNMSIsICJDMVFDIiwgIkNDTDIiLCAiT0FTMyIsICJNWDEiKQpnZW5lcyRhbmFseXNpczEgPC0gYygiSFNQQTFBIiwgIkZNQzEtTFVDN0wyIiwgIkhTUEExQiIsCSJBQzAxMTUxMS40IiwgIlBQUDFSMTEiLCAiQUwxMzkzMDAuMSIsICJMWTZHTFk2QyIpCmdlbmVzJGFuYWx5c2lzMiA8LSBjKCJJVEdBWCIsICJPQVMzIiwgIklGSVRNMSIsICJNWDEiLCAiQzFRQyIsICJNWDIiLCAiQ0NMMiIpCmdlbmVzJGFkZGl0aW9uYWwgPC0gYygiQzFRVE5GMiIsICJMWVZFMSIsICJUUkVNMSIsICJGT0xSMiIsICJDMVFCIiwJIkNDTDIiLCAiVE5GUlNGMTBDIiwgIkNYQ0w5IiwgIklMMVIyIiwgIklMMzZBIiwgIkNEMjgiLCAiT0FTMSIsICJJTDFSTiIsICJDRDM2IiwgIkNYQ1IyIiwJIlNFUlBJTkcxIiwgIkNYQ1IxIiwgIlRORlJTRjEwQyIsICJDMVFBIiwgIkhDU1QiLCAiSUwzNkEiLCAiSUw0UiIsICJMWTk2IiwgIklMMVIyIiwgIkNYQ1IyIiwgIkNYQ0wyIiwgIlMxMDBBNyIsICJJRklUTTMiLCAiU0VMRU5PTSIsICJTRUxFTk9QIiwgIkMzQVIxIiwgIkNDTDIiLCAiQ0NMOCIpCmdlbmVzJGVudHJ5IDwtIGMoIkFDRTIiLCAiVE1QUlNTMiIsICJCU0ciLCAiRFBQNCIsICJDVFNMIiwgIkNUU0IiLCAiRlVSSU4iKQoKYWxsLmdlbmVzIDwtIGMoZ2VuZXMkZm9jdXNlZCwgZ2VuZXMkYW5hbHlzaXMxLCBnZW5lcyRhbmFseXNpczIsIGdlbmVzJGFkZGl0aW9uYWwsIGdlbmVzJGVudHJ5KSAlPiUgCiAgdW5pcXVlKCkgJT4lIAogIHNvcnQoKQpgYGAKCiMgUGxvdHMKIyMgRG90cGxvdCBmb3IgYWxsIGdlbmVzCgpgYGB7cn0KIyBkb3RwbG90IGZ1bmN0aW9uCkRvdFBsb3QyIDwtIGZ1bmN0aW9uKG9iamVjdCA9IHNldXIsIGFzc2F5ID0gIlNDVCIsIGZlYXR1cmVzLCB0aXRsZSA9ICIiLCAuLi4pIHsKICBwIDwtIERvdFBsb3Qob2JqZWN0LCAKICAgICAgICAgICAgICAgYXNzYXkgPSBhc3NheSwKICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBmZWF0dXJlcywgCiAgICAgICAgICAgICAgIGRvdC5zY2FsZSA9IDQsIAogICAgICAgICAgICAgICBkb3QubWluID0gMC4wMSwKICAgICAgICAgICAgICAgLi4uKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgbGFicyhjYXB0aW9uID0gcGFzdGUwKCJzY3RyYW5zZm9ybSBub3JtYWxpemVkIGV4cHJlc3Npb24iKSwgdGl0bGUgPSB0aXRsZSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpLAogICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuMSksCiAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNzUsICJsaW5lIikpCiAgCiAgcmV0dXJuKHApCn0KYGBgCgpgYGB7ciBmaWcuYXNwPTEuMiwgZmlnLndpZHRoPTYuNX0KRG90UGxvdDIoZmVhdHVyZXMgPSBhbGwuZ2VuZXMpCgpjb3dwbG90OjpnZ3NhdmUyKGxhc3RfcGxvdCgpLCAKICAgICAgICAgICAgICAgICBmaWxlbmFtZSA9ICIuLi9yZXN1bHRzLzAzX2RlLWdlbmVzL3Bsb3RzL2RvdHBsb3RfYWxsLWdlbmVzLnBkZiIsIAogICAgICAgICAgICAgICAgIHdpZHRoID0gNi41LCBoZWlnaHQgPSA4LCB1bml0cyA9ICJpbiIpCmBgYAoKIyMgSW5kaXZpZHVhbCBnZW5lcwpgYGB7cn0KIyB2aW9saW4gZnVuY3Rpb24KVmxuUGxvdDIgPC0gZnVuY3Rpb24ob2JqZWN0ID0gc2V1ciwgYXNzYXkgPSAiU0NUIiwgZmVhdHVyZSwgLi4uKSB7CiAgcCA8LSBWbG5QbG90KG9iamVjdCA9IG9iamVjdCwgCiAgICAgICAgICAgICAgIGZlYXR1cmVzID0gZmVhdHVyZSwgCiAgICAgICAgICAgICAgIGFzc2F5ID0gYXNzYXksIAogICAgICAgICAgICAgICBzYW1lLnkubGltcyA9IEZBTFNFLAogICAgICAgICAgICAgICBzcGxpdC5ieSA9ICJjb3ZpZCIsIAogICAgICAgICAgICAgICBzcGxpdC5wbG90ID0gVFJVRSwKICAgICAgICAgICAgICAgcHQuc2l6ZSA9IDAsCiAgICAgICAgICAgICAgIC4uLikgKyAKICAgIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZSgKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgY29sb3VyID0gImJsYWNrIiksCiAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuMiksCiAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShzaXplID0gMC4yNSksCiAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuMjUpLAogICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEsIHZqdXN0ID0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDYsIGNvbG9yID0gImJsYWNrIiksCiAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LCBjb2xvciA9ICJibGFjayIpLAogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiwgY29sb3IgPSAiYmxhY2siKSwKICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUwLCAibGluZXMiKSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygxLCAxKSwKICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwKICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDEsIDApLAogICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiwgY29sb3VyID0gImJsYWNrIikKICAgICkKICAKICBwJGxheWVyc1tbMV1dJGFlc19wYXJhbXMkc2l6ZSA9IDAuMjUgIyB2aW9saW4gc3Ryb2tlCiAgCiAgcmV0dXJuKHApCn0KYGBgCgpgYGB7cn0KIyB1bWFwIGZ1bmN0aW9uCkZlYXR1cmVQbG90MiA8LSBmdW5jdGlvbihvYmplY3QgPSBzZXVyLCBmZWF0dXJlLCAuLi4pIHsKICBEZWZhdWx0QXNzYXkob2JqZWN0KSA8LSAiU0NUIgogIEZlYXR1cmVQbG90KG9iamVjdCwgCiAgICAgICAgICAgICAgZmVhdHVyZSA9IGZlYXR1cmUsIAogICAgICAgICAgICAgIHNwbGl0LmJ5ID0gImNvdmlkIiwKICAgICAgICAgICAgICBwdC5zaXplID0gMC4xLCAKICAgICAgICAgICAgICBvcmRlciA9IFRSVUUsIAogICAgICAgICAgICAgIG1pbi5jdXRvZmYgPSAicTEwIiwgCiAgICAgICAgICAgICAgY29tYmluZSA9IFRSVUUsCiAgICAgICAgICAgICAgLi4uKSAmCiAgICBwbG90X2Fubm90YXRpb24odGl0bGUgPSBmZWF0dXJlKSAmCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuMjUpLAogICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC41MCwgImxpbmUiKSwKICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LCBhbmdsZSA9IDkwLCBoanVzdCA9IDEpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgICAgYXhpcy50aXRsZS55LnJpZ2h0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKfQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9Mi43NSwgZmlnLmFzcD0xfQoKZm9yKGkgaW4gYWxsLmdlbmVzW2FsbC5nZW5lcyAlaW4lIHJvd25hbWVzKHNldXIpXSkgewogIHZwbG90IDwtIFZsblBsb3QyKGZlYXR1cmUgPSBpKQogIGZwbG90IDwtIEZlYXR1cmVQbG90MihmZWF0dXJlID0gaSwgbWF4LmN1dG9mZiA9ICJxOTkiKQogIAogIGNvd3Bsb3Q6Omdnc2F2ZTIodnBsb3QsIAogICAgICAgICAgICAgICAgICAgZmlsZW5hbWUgPSBwYXN0ZTAoIi4uL3Jlc3VsdHMvMDNfZGUtZ2VuZXMvcGxvdHMvIiwgaSwgIl92aW9saW5wbG90LnBkZiIpLAogICAgICAgICAgICAgICAgICAgd2lkdGggPSAzLjUsIGhlaWdodCA9IDIsIHVuaXRzID0gImluIikKICAKICBjb3dwbG90OjpnZ3NhdmUyKGZwbG90LCAKICAgICAgICAgICAgICAgICAgIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9yZXN1bHRzLzAzX2RlLWdlbmVzL3Bsb3RzLyIsIGksICJfb24tdW1hcC5wbmciKSwKICAgICAgICAgICAgICAgICAgIHdpZHRoID0gMy41LCBoZWlnaHQgPSAyLjUsIHVuaXRzID0gImluIikKICAKICB2ZiA8LSB2cGxvdCArIGZwbG90ICsgCiAgcGxvdF9sYXlvdXQobmNvbCA9IDEsIHdpZHRocyA9IGMoMSwgMC41KSkKICBwcmludCh2ZikKfQpgYGAKCkZvciBzb21lIGdlbmVzLCB0aGUgdW1hcCBwbG90cyBhbmQgdmlvbGluIHBsb3RzIHNlZW0gdG8gZGlzYWdyZWUgd2l0aCBlYWNoIG90aGVyLiBUaGF0IGlzLCB0aGUgZ2VuZSBpcyBleHByZXNzZWQgYXQgaGlnaGVyIGxldmVsIGluICJjb3ZpZCIgdGhhbiAiY29udHJvbCIgYWNjb3JkaW5nIHRvIHRoZSB2aW9saW4gcGxvdCwgYnV0IHRoZSBjb2xvdXJzIGFwcGVhciBzdHJvbmdlciBmb3IgImNvbnRyb2wiIG9uIHVtYXAgcGxvdHMuIEkgdGhpbmsgdGhpcyBpcyBzaW1wbHkgYmVjYXVzZSBvZiB0aGUgZGlmZmVyaW5nIG51bWJlciBvZiBjZWxscyBmcm9tICJjb250cm9sIiBhbmQgImNvdmlkIi4gV2UgaGF2ZSBmZXdlciBjZWxscyBmcm9tICJjb3ZpZCIgc2FtcGxlcyAoYXMgaXMgZXZpZGVudCBhbHNvIG9uIHRoZSB1bWFwIHBsb3RzKSwgc28gdGhlIGxpZ2h0bmVzcyBvciBzcGFyc2VuZXNzIG9mIGJsdWUgb24gdW1hcCBwbG90cyBqdXN0IHJlZmxlY3QgdGhhdC4gVmlvbGluIHBsb3RzIG9uIHRoZSBvdGhlciBoYW5kIHNjYWxlIHRoZSB3aWR0aCBvZiB2aW9saW5zIHRvIHRoZSB0b3RhbCBudW1iZXIgb2YgY2VsbHMgaW4gZWFjaCBncm91cCwgc28gdGhpcyBkaWZmZXJlbmNlIGlzIG5vdCBzZWVuIGluIHZpb2xpbiBwbG90cy4KCiMgU2Vzc2lvbiBJbmZvCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoK